package com.enjoyor.soa.traffic.ping.efoms.dubbo.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.rpc.RpcContext;
import com.enjoyor.soa.traffic.api.dto.MessageInfoDto;
import com.enjoyor.soa.traffic.api.dto.efoms.PingResultDto;
import com.enjoyor.soa.traffic.api.service.dubbo.CallbackListener;
import com.enjoyor.soa.traffic.api.service.dubbo.efoms.CallBackService;
import com.enjoyor.soa.traffic.frame.annotation.Argument;
import com.enjoyor.soa.traffic.frame.annotation.InterfaceMethods;
import com.enjoyor.soa.traffic.frame.annotation.Method;
import com.enjoyor.soa.traffic.ping.efoms.common.Global;
import com.enjoyor.soa.traffic.util.enums.EnumNotifyObject;
import com.enjoyor.soa.traffic.util.enums.EnumOprType;
import com.enjoyor.soa.traffic.util.helper.LoggerHelper;
import com.enjoyor.soa.traffic.util.helper.TimeHelper;

@Service(version = "1.0.0", timeout = 4000)
public class DubboCallbackServiceImpl implements CallBackService {

    private Map<String, CallbackListener> listeners = new ConcurrentHashMap<String, CallbackListener>();

    public DubboCallbackServiceImpl() {
        // 监听进程
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        while (!Global.resultQueue.isEmpty() && Global.resultQueue.size() >= 100) {
                            //Object obj = Global.resultQueue.poll();
                        	List<PingResultDto> list = new ArrayList<PingResultDto>();
                            int num = Global.resultQueue.drainTo(list, 100);
                            sendMessage(list);
                        }
                        Thread.sleep(5000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

        });
        t.setDaemon(true);
        t.start();
    }

    /**
     * 发送信息
     *
     * @param obj
     */
    @SuppressWarnings("unchecked")
	private void sendMessage(Object obj) {
        for (Entry<String, CallbackListener> entry : listeners.entrySet()) {
            try {
                MessageInfoDto dto = new MessageInfoDto();
                //if (obj.getClass().equals(PingResultDto.class)) {
                    dto = new MessageInfoDto(EnumOprType.EFOMS_PING_DATA, (List<PingResultDto>) obj, EnumNotifyObject.EFOMS_PING_RESULT);
                //}
                entry.getValue().update(dto);
            } catch (Exception e) {
                listeners.remove(entry.getKey());
                LoggerHelper.LOG.info("************消息回调增加订阅者key为：" + entry.getKey() + "************");
                LoggerHelper.LOG.info(e);
            }
        }
    }

   @InterfaceMethods(methods = { @Method(name = "addListener", retries = 0, timeout = 3000, arguments = {
           @Argument(index = 1, callback = true) }) })
    @Override
    public String addListener(String value, CallbackListener listener) {
        String key = value;
        try {
            if (value == null || value.equals("")) {
                key = TimeHelper.getUniqueString();
            }
            LoggerHelper.LOG.info("************消息回调增加订阅者key为：" + key + "************");
            listeners.put(key, listener);

        } catch (Exception ex) {
            LoggerHelper.LOG.error(ex);
        }
        return key;
    }

    @Override
    public Boolean removeListener(String key){
        Boolean result = true;
        try {
            listeners.remove(key);
        } catch (Exception ex) {
            LoggerHelper.LOG.error(ex);
        }
        return !listeners.containsKey(key);
    }

    @SuppressWarnings("unused")
    @Override
    public boolean isActive(String key) {
        String clientIP = RpcContext.getContext().getRemoteHost(); // 获取调用方IP地址
        /*key = key + clientIP;*/
        if (key != null && this.listeners.containsKey(key)) {
            return true;
        } else {
            return false;
        }
    }
}
